using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging;
using YahooFinanceApi;

namespace MT5Trade.Models.MarketData
{
    /// <summary>
    /// Yahoo Finance数据提供者实现
    /// </summary>
    public class YahooFinanceDataProvider : IMarketDataProvider
    {
        private readonly IMemoryCache _cache;
        private readonly HttpClient _httpClient;
        private readonly ILogger<YahooFinanceDataProvider> _logger;
        private readonly TimeSpan _cacheExpiration = TimeSpan.FromHours(24); // 增加缓存时间到24小时，减少API调用
        private readonly SemaphoreSlim _rateLimitSemaphore = new SemaphoreSlim(1, 1);
        private DateTime _lastRequestTime = DateTime.MinValue;
        private readonly TimeSpan _minRequestInterval = TimeSpan.FromSeconds(2); // 限制每2秒一个请求，避免429错误
        private readonly FileDataCache _fileCache;

        public YahooFinanceDataProvider(
            IMemoryCache cache = null,
            HttpClient httpClient = null,
            ILogger<YahooFinanceDataProvider> logger = null,
            FileDataCache fileCache = null)
        {
            _cache = cache ?? new MemoryCache(new MemoryCacheOptions());
            _httpClient = httpClient ?? new HttpClient();
            _logger = logger ?? CreateDefaultLogger();
            _fileCache = fileCache ?? new FileDataCache();
        }

        private static ILogger<YahooFinanceDataProvider> CreateDefaultLogger()
        {
            using var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
            return loggerFactory.CreateLogger<YahooFinanceDataProvider>();
        }

        public async Task<List<MarketTick>> GetHistoricalDataAsync(
            string symbol,
            DateTime startDate,
            DateTime endDate,
            Interval interval = Interval.Daily)
        {
            // 首先检查文件缓存
            var fileCachedData = await _fileCache.GetCachedHistoricalDataAsync(symbol, startDate, endDate, interval);
            if (fileCachedData != null)
            {
                _logger.LogInformation($"从文件缓存加载 {symbol} 数据: {fileCachedData.Count} 条记录");
                return fileCachedData;
            }

            var cacheKey = $"hist_{symbol}_{startDate:yyyyMMdd}_{endDate:yyyyMMdd}_{interval}";

            return await _cache.GetOrCreateAsync(cacheKey, async entry =>
            {
                entry.SlidingExpiration = _cacheExpiration;

                try
                {
                    // 应用速率限制
                    await ApplyRateLimitAsync();

                    // 转换为Yahoo Finance的周期格式
                    var period = ConvertToYahooPeriod(interval);

                    // 获取历史数据，带重试机制
                    var history = await RetryWithExponentialBackoffAsync(async () =>
                        await Yahoo.GetHistoricalAsync(
                            symbol,
                            startDate,
                            endDate,
                            period),
                        maxRetries: 3);

                    // 转换为我们的数据模型
                    var data = history.Select(h => new MarketTick
                    {
                        Time = h.DateTime,
                        Open = (decimal)h.Open,
                        High = (decimal)h.High,
                        Low = (decimal)h.Low,
                        Close = (decimal)h.Close,
                        AdjustedClose = (decimal)h.AdjustedClose,
                        Volume = h.Volume,
                        Symbol = symbol,
                        Volatility = CalculateIntraDayVolatility(h)
                    }).ToList();

                    // 保存到文件缓存
                    await _fileCache.SaveHistoricalDataAsync(symbol, startDate, endDate, interval, data);
                    _logger.LogInformation($"数据已保存到文件缓存: {symbol}, {data.Count} 条记录");

                    return data;
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"获取{symbol}历史数据失败");
                    return new List<MarketTick>();
                }
            });
        }

        public async Task<MarketTick> GetLatestQuoteAsync(string symbol)
        {
            var cacheKey = $"quote_{symbol}";

            return await _cache.GetOrCreateAsync(cacheKey, async entry =>
            {
                entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1);

                try
                {
                    // 应用速率限制
                    await ApplyRateLimitAsync();

                    var securities = await RetryWithExponentialBackoffAsync(async () =>
                        await Yahoo.Symbols(symbol)
                            .Fields(Field.Symbol, Field.RegularMarketPrice,
                                    Field.RegularMarketOpen, Field.RegularMarketDayHigh,
                                    Field.RegularMarketDayLow, Field.RegularMarketVolume,
                                    Field.RegularMarketTime, Field.RegularMarketPreviousClose)
                            .QueryAsync(),
                        maxRetries: 3);

                    var security = securities[symbol];

                    return new MarketTick
                    {
                        Symbol = symbol,
                        Time = DateTimeOffset.FromUnixTimeSeconds(
                            security.RegularMarketTime).DateTime,
                        Open = (decimal)security.RegularMarketOpen,
                        High = (decimal)security.RegularMarketDayHigh,
                        Low = (decimal)security.RegularMarketDayLow,
                        Close = (decimal)security.RegularMarketPrice,
                        AdjustedClose = (decimal)security.RegularMarketPrice,
                        Volume = security.RegularMarketVolume
                    };
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, $"获取{symbol}最新报价失败");
                    return null;
                }
            });
        }

        public async Task<Dictionary<string, MarketTick>> GetMultipleQuotesAsync(List<string> symbols)
        {
            var result = new Dictionary<string, MarketTick>();

            try
            {
                // 应用速率限制
                await ApplyRateLimitAsync();

                var securities = await RetryWithExponentialBackoffAsync(async () =>
                    await Yahoo.Symbols(symbols.ToArray())
                        .Fields(Field.Symbol, Field.RegularMarketPrice,
                                Field.RegularMarketOpen, Field.RegularMarketDayHigh,
                                Field.RegularMarketDayLow, Field.RegularMarketVolume,
                                Field.RegularMarketTime)
                        .QueryAsync(),
                    maxRetries: 3);

                foreach (var symbol in symbols)
                {
                    if (securities.ContainsKey(symbol))
                    {
                        var security = securities[symbol];
                        result[symbol] = new MarketTick
                        {
                            Symbol = symbol,
                            Time = DateTimeOffset.FromUnixTimeSeconds(
                                security.RegularMarketTime).DateTime,
                            Open = (decimal)security.RegularMarketOpen,
                            High = (decimal)security.RegularMarketDayHigh,
                            Low = (decimal)security.RegularMarketDayLow,
                            Close = (decimal)security.RegularMarketPrice,
                            Volume = security.RegularMarketVolume
                        };
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "批量获取报价失败");
            }

            return result;
        }

        public async Task<MarketVolatility> CalculateVolatilityAsync(
            string symbol,
            int lookbackDays = 20)
        {
            var endDate = DateTime.Now;
            var startDate = endDate.AddDays(-lookbackDays * 2); // 获取更多数据以计算不同周期

            var data = await GetHistoricalDataAsync(symbol, startDate, endDate);

            if (data == null || data.Count < lookbackDays)
            {
                return new MarketVolatility
                {
                    Symbol = symbol,
                    CalculatedAt = DateTime.Now,
                    Regime = VolatilityRegime.Normal
                };
            }

            // 计算日收益率
            var returns = new List<double>();
            for (int i = 1; i < data.Count; i++)
            {
                var dailyReturn = (double)((data[i].Close - data[i - 1].Close) / data[i - 1].Close);
                returns.Add(dailyReturn);
            }

            // 计算各周期波动率
            var dailyVol = CalculateStandardDeviation(returns.TakeLast(lookbackDays));
            var weeklyVol = CalculateStandardDeviation(returns.TakeLast(5));
            var monthlyVol = CalculateStandardDeviation(returns);

            // 年化波动率（假设252个交易日）
            var annualizedVol = dailyVol * Math.Sqrt(252);

            // 确定波动率状态
            var regime = DetermineVolatilityRegime(annualizedVol);

            return new MarketVolatility
            {
                Symbol = symbol,
                CalculatedAt = DateTime.Now,
                Daily = dailyVol,
                Weekly = weeklyVol * Math.Sqrt(5),
                Monthly = monthlyVol * Math.Sqrt(21),
                Annualized = annualizedVol,
                Regime = regime,
                Percentile = CalculateVolatilityPercentile(annualizedVol),
                VIXEquivalent = annualizedVol * 100 // 简化的VIX等效值
            };
        }

        public async Task<List<GapEvent>> IdentifyGapsAsync(
            string symbol,
            DateTime startDate,
            DateTime endDate,
            double minGapPercentage = 0.01)
        {
            var data = await GetHistoricalDataAsync(symbol, startDate, endDate);
            var gaps = new List<GapEvent>();

            if (data == null || data.Count < 2)
                return gaps;

            for (int i = 1; i < data.Count; i++)
            {
                var prevClose = data[i - 1].Close;
                var currOpen = data[i].Open;
                var gapSize = Math.Abs(currOpen - prevClose);
                var gapPct = (double)(gapSize / prevClose);

                if (gapPct >= minGapPercentage)
                {
                    var gapType = DetermineGapType(data, i, gapPct);
                    var gapEvent = new GapEvent
                    {
                        Time = data[i].Time,
                        Symbol = symbol,
                        GapSize = gapSize,
                        GapPercentage = (decimal)gapPct,
                        Type = gapType,
                        PreviousClose = prevClose,
                        CurrentOpen = currOpen,
                        Description = GenerateGapDescription(gapType, gapPct)
                    };

                    // 检查缺口是否被填补
                    CheckGapFill(gapEvent, data, i);
                    gaps.Add(gapEvent);
                }
            }

            return gaps;
        }

        public async Task<Dictionary<string, double>> CalculateCorrelationMatrixAsync(
            List<string> symbols,
            int lookbackDays = 30)
        {
            var correlationMatrix = new Dictionary<string, double>();

            if (symbols.Count < 2)
            {
                if (symbols.Count == 1)
                    correlationMatrix[$"{symbols[0]}_{symbols[0]}"] = 1.0;
                return correlationMatrix;
            }

            var endDate = DateTime.Now;
            var startDate = endDate.AddDays(-lookbackDays);

            // 获取所有品种的历史数据
            var allData = new Dictionary<string, List<double>>();
            foreach (var symbol in symbols)
            {
                var data = await GetHistoricalDataAsync(symbol, startDate, endDate);
                if (data != null && data.Count > 1)
                {
                    var returns = new List<double>();
                    for (int i = 1; i < data.Count; i++)
                    {
                        returns.Add((double)((data[i].Close - data[i - 1].Close) / data[i - 1].Close));
                    }
                    allData[symbol] = returns;
                }
            }

            // 计算相关性
            foreach (var symbol1 in symbols)
            {
                foreach (var symbol2 in symbols)
                {
                    if (allData.ContainsKey(symbol1) && allData.ContainsKey(symbol2))
                    {
                        var correlation = CalculateCorrelation(allData[symbol1], allData[symbol2]);
                        correlationMatrix[$"{symbol1}_{symbol2}"] = correlation;
                    }
                }
            }

            return correlationMatrix;
        }

        public async Task<MarketRegime> GetMarketRegimeAsync(string symbol)
        {
            var volatility = await CalculateVolatilityAsync(symbol, 20);
            var historicalData = await GetHistoricalDataAsync(
                symbol,
                DateTime.Now.AddDays(-60),
                DateTime.Now);

            if (historicalData == null || historicalData.Count < 20)
                return MarketRegime.RangeBound;

            // 基于波动率判断
            if (volatility.Annualized > 0.4)
                return MarketRegime.Crisis;
            if (volatility.Annualized > 0.25)
                return MarketRegime.Volatile;

            // 分析趋势
            var trend = AnalyzeTrend(historicalData);
            if (Math.Abs(trend) > 0.001)
                return MarketRegime.Trending;

            return MarketRegime.RangeBound;
        }

        public async Task<Dictionary<string, List<MarketTick>>> GetBulkHistoricalDataAsync(
            List<string> symbols,
            DateTime startDate,
            DateTime endDate)
        {
            var result = new Dictionary<string, List<MarketTick>>();

            // 并行获取多个品种的数据
            var tasks = symbols.Select(async symbol =>
            {
                var data = await GetHistoricalDataAsync(symbol, startDate, endDate);
                return new { Symbol = symbol, Data = data };
            });

            var results = await Task.WhenAll(tasks);

            foreach (var item in results)
            {
                if (item.Data != null && item.Data.Count > 0)
                {
                    result[item.Symbol] = item.Data;
                }
            }

            return result;
        }

        #region 辅助方法

        private Period ConvertToYahooPeriod(Interval interval)
        {
            // YahooFinanceApi中Period的实际值
            // Period.Daily, Period.Weekly, Period.Monthly 用于历史数据
            // 对于日内数据，免费API有限制，我们使用Daily作为后备
            return interval switch
            {
                // 免费API不支持日内数据，但我们可以尝试获取最近的日线数据
                Interval.OneMinute => Period.Daily,
                Interval.FiveMinutes => Period.Daily,
                Interval.FifteenMinutes => Period.Daily,
                Interval.ThirtyMinutes => Period.Daily,
                Interval.Hourly => Period.Daily,
                Interval.Daily => Period.Daily,
                Interval.Weekly => Period.Weekly,
                Interval.Monthly => Period.Monthly,
                _ => Period.Daily
            };
        }

        private decimal CalculateIntraDayVolatility(Candle candle)
        {
            if (candle.Open == 0) return 0;
            var range = (decimal)(candle.High - candle.Low);
            return range / (decimal)candle.Open;
        }

        private GapType DetermineGapType(List<MarketTick> data, int index, double gapPct)
        {
            // 基于缺口大小和位置判断类型
            if (gapPct > 0.03) return GapType.Breakaway;

            if (index > 5 && IsTrending(data, index - 5, index))
                return GapType.Continuation;

            if (index < data.Count - 2 && IsReversal(data, index))
                return GapType.Exhaustion;

            return GapType.Common;
        }

        private bool IsTrending(List<MarketTick> data, int startIndex, int endIndex)
        {
            if (startIndex < 0 || endIndex >= data.Count) return false;

            var prices = data.Skip(startIndex).Take(endIndex - startIndex)
                             .Select(d => (double)d.Close).ToList();

            var trend = CalculateTrendSlope(prices);
            return Math.Abs(trend) > 0.001;
        }

        private bool IsReversal(List<MarketTick> data, int index)
        {
            if (index >= data.Count - 2) return false;

            var prevTrend = data[index].Close - data[index - 1].Close;
            var nextTrend = data[index + 1].Close - data[index].Close;

            return (prevTrend > 0 && nextTrend < 0) || (prevTrend < 0 && nextTrend > 0);
        }

        private void CheckGapFill(GapEvent gap, List<MarketTick> data, int gapIndex)
        {
            for (int i = gapIndex + 1; i < data.Count && i < gapIndex + 20; i++)
            {
                var isUpGap = gap.CurrentOpen > gap.PreviousClose;

                if ((isUpGap && data[i].Low <= gap.PreviousClose) ||
                    (!isUpGap && data[i].High >= gap.PreviousClose))
                {
                    gap.IsFilled = true;
                    gap.FillDate = data[i].Time;
                    gap.BarsToFill = i - gapIndex;
                    break;
                }
            }
        }

        private string GenerateGapDescription(GapType type, double gapPct)
        {
            var percentStr = $"{gapPct:P2}";
            return type switch
            {
                GapType.Breakaway => $"突破缺口 ({percentStr})，可能预示新趋势开始",
                GapType.Continuation => $"持续缺口 ({percentStr})，趋势延续信号",
                GapType.Exhaustion => $"竭尽缺口 ({percentStr})，可能预示趋势结束",
                GapType.Common => $"普通缺口 ({percentStr})，短期内可能回补",
                _ => $"未分类缺口 ({percentStr})"
            };
        }

        private double CalculateStandardDeviation(IEnumerable<double> values)
        {
            var valuesList = values.ToList();
            if (!valuesList.Any()) return 0;

            var mean = valuesList.Average();
            var sumSquaredDiff = valuesList.Sum(v => Math.Pow(v - mean, 2));
            return Math.Sqrt(sumSquaredDiff / valuesList.Count);
        }

        private VolatilityRegime DetermineVolatilityRegime(double annualizedVol)
        {
            if (annualizedVol < 0.1) return VolatilityRegime.Low;
            if (annualizedVol < 0.2) return VolatilityRegime.Normal;
            if (annualizedVol < 0.4) return VolatilityRegime.High;
            return VolatilityRegime.Extreme;
        }

        private double CalculateVolatilityPercentile(double volatility)
        {
            // 简化的百分位计算（基于历史经验值）
            if (volatility < 0.1) return 0.2;
            if (volatility < 0.15) return 0.4;
            if (volatility < 0.2) return 0.6;
            if (volatility < 0.3) return 0.8;
            return 0.95;
        }

        private double CalculateCorrelation(List<double> series1, List<double> series2)
        {
            if (series1.Count != series2.Count || series1.Count == 0)
                return 0;

            var mean1 = series1.Average();
            var mean2 = series2.Average();

            var covariance = series1.Zip(series2, (x, y) => (x - mean1) * (y - mean2)).Average();
            var std1 = Math.Sqrt(series1.Average(x => Math.Pow(x - mean1, 2)));
            var std2 = Math.Sqrt(series2.Average(y => Math.Pow(y - mean2, 2)));

            if (std1 == 0 || std2 == 0) return 0;

            return covariance / (std1 * std2);
        }

        private double AnalyzeTrend(List<MarketTick> data)
        {
            if (data == null || data.Count < 2) return 0;

            var prices = data.Select(d => (double)d.Close).ToList();
            return CalculateTrendSlope(prices);
        }

        private double CalculateTrendSlope(List<double> prices)
        {
            if (prices.Count < 2) return 0;

            var n = prices.Count;
            var xSum = 0.0;
            var ySum = 0.0;
            var xySum = 0.0;
            var x2Sum = 0.0;

            for (int i = 0; i < n; i++)
            {
                xSum += i;
                ySum += prices[i];
                xySum += i * prices[i];
                x2Sum += i * i;
            }

            var denominator = n * x2Sum - xSum * xSum;
            if (denominator == 0) return 0;

            return (n * xySum - xSum * ySum) / denominator;
        }

        #endregion

        #region 批量数据管理

        /// <summary>
        /// 批量下载并缓存数据
        /// </summary>
        public async Task<Dictionary<string, List<MarketTick>>> BatchDownloadAndCacheAsync(
            List<string> symbols,
            int lookbackDays = 30,
            Interval interval = Interval.Daily)
        {
            var endDate = DateTime.UtcNow;
            var startDate = endDate.AddDays(-lookbackDays);

            _logger.LogInformation($"开始批量下载: {symbols.Count} 个品种, {lookbackDays} 天数据");

            var result = new Dictionary<string, List<MarketTick>>();
            var successCount = 0;
            var cacheHitCount = 0;
            var failureCount = 0;

            foreach (var symbol in symbols)
            {
                try
                {
                    // 首先检查文件缓存
                    var cachedData = await _fileCache.GetCachedHistoricalDataAsync(symbol, startDate, endDate, interval);
                    if (cachedData != null)
                    {
                        result[symbol] = cachedData;
                        cacheHitCount++;
                        _logger.LogInformation($"{symbol}: 使用文件缓存 ({cachedData.Count} 条记录)");
                        continue;
                    }

                    // 调用API获取数据
                    var data = await GetHistoricalDataAsync(symbol, startDate, endDate, interval);
                    if (data != null && data.Any())
                    {
                        result[symbol] = data;
                        successCount++;
                        _logger.LogInformation($"{symbol}: 下载成功 ({data.Count} 条记录)");
                    }
                    else
                    {
                        failureCount++;
                        _logger.LogWarning($"{symbol}: 无数据");
                    }
                }
                catch (Exception ex)
                {
                    failureCount++;
                    _logger.LogError($"{symbol}: 下载失败 - {ex.Message}");
                }
            }

            _logger.LogInformation($"批量下载完成 - 缓存命中: {cacheHitCount}, 新下载: {successCount}, 失败: {failureCount}");

            // 清理过期缓存
            await _fileCache.CleanupExpiredCacheAsync();

            return result;
        }

        /// <summary>
        /// 获取缓存统计信息
        /// </summary>
        public CacheStatistics GetCacheStatistics()
        {
            return _fileCache.GetStatistics();
        }

        /// <summary>
        /// 预热常用品种缓存
        /// </summary>
        public async Task WarmupCommonSymbolsAsync()
        {
            var commonSymbols = new List<string>
            {
                "SPY", "QQQ", "DIA", "IWM",           // 美股ETF
                "EURUSD=X", "GBPUSD=X", "USDJPY=X",   // 外汇
                "GC=F", "CL=F", "SI=F",                // 商品期货
                "^GSPC", "^DJI", "^IXIC"              // 指数
            };

            await BatchDownloadAndCacheAsync(commonSymbols, 30);
        }

        #endregion

        #region 速率限制和重试机制

        private async Task ApplyRateLimitAsync()
        {
            await _rateLimitSemaphore.WaitAsync();
            try
            {
                var timeSinceLastRequest = DateTime.UtcNow - _lastRequestTime;
                if (timeSinceLastRequest < _minRequestInterval)
                {
                    var delay = _minRequestInterval - timeSinceLastRequest;
                    _logger.LogDebug($"Rate limiting: delaying {delay.TotalMilliseconds}ms");
                    await Task.Delay(delay);
                }
                _lastRequestTime = DateTime.UtcNow;
            }
            finally
            {
                _rateLimitSemaphore.Release();
            }
        }

        private async Task<T> RetryWithExponentialBackoffAsync<T>(
            Func<Task<T>> operation,
            int maxRetries = 3)
        {
            var retryCount = 0;
            var delay = TimeSpan.FromSeconds(5); // 增加初始延迟到5秒

            while (retryCount < maxRetries)
            {
                try
                {
                    return await operation();
                }
                catch (Exception ex) when (ex.Message.Contains("429") || ex.Message.Contains("Too Many Requests"))
                {
                    retryCount++;
                    if (retryCount >= maxRetries)
                    {
                        _logger.LogError($"达到最大重试次数 ({maxRetries})，仍然收到429错误");
                        throw;
                    }

                    _logger.LogWarning($"收到429错误，等待 {delay.TotalSeconds} 秒后重试 (重试 {retryCount}/{maxRetries})");
                    await Task.Delay(delay);
                    delay = TimeSpan.FromSeconds(delay.TotalSeconds * 2); // 指数退避
                }
                catch (Exception)
                {
                    throw;
                }
            }

            throw new InvalidOperationException("不应该到达这里");
        }

        #endregion
    }
}